/* -----------------
* brief
* 1. this is code gen by tools
 */

package service

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/chanxuehong/wechat/mch/mmpaymkttransfers/promotion"
	"github.com/chanxuehong/wechat/mch/pay"
	"github.com/mjiulee/lego"
	"github.com/mjiulee/lego/utils"
	"saas_sys_base/common"
	. "saas_sys_base/modules/appmanager/service"
	. "saas_sys_base/modules/sysOrders/models"
	. "saas_sys_base/modules/tenant/models"
	. "saas_sys_base/modules/tenant/service"
	. "saas_sys_base/modules/user/service"
	. "saas_sys_base/modules/wechat/service"
)

type OrdersService struct {
	// add your model here
	tbOrders SysOrders
	tbOrderDetail SysOrderDetail

	appProductService AppProductService
	AppManagerService AppManagerService

	appTenantUserRelService AppTenantUserRelService //这里后续可以移到一个中间件中
	tenantService TenantService //这里后续可以移到一个中间件中
	wxUserService WxUserService

	wxPayService WxPayService
}

func (t *OrdersService) ListOrders(keyword string, page, psize int, orderField, order string) ([]map[string]string, int64, error) {
	// 业务查询
	queryMap := map[string]interface{}{
		"table":  map[string]string{"table": "tb_orders", "alias": "t1"},
		"fields": []string{"t1.*"},
		"join":   []map[string]string{
			// map[string]string{"table": "tb_xx as t2", "on": "t2.xid = t1.id"},
		},
		"where": []lego.QMapWhereField{
			{"t1.if_del", "=", 0, "AND", false},
		},
		"search": map[string]string{
			//"t1.id": req.Keyword,
		},
		"orders": []string{"t1.id asc"},
		"page": map[string]int{
			"page":  page,
			"psize": psize,
		},
	}

	if orderField != "" && order != "" {
		orderStr := fmt.Sprintf("t1.%s %s", orderField, order)
		queryMap["orders"] = []string{orderStr, "t1.cdate asc"}
	}

	return lego.QueryListByMap(queryMap)
}

func (t *OrdersService) ListOrdersByWho(who *common.Who, orderCode, userName, mobile, beginTime, endTime, productName string, orderType int, shopids []int64, page, psize int, orderField, order string, orderStatus int) ([]*SysOrders, int64, error) {
	return t.tbOrders.ListSysOrdersByWho(who, orderCode, userName, mobile, beginTime, endTime, productName, orderType, shopids, page, psize, orderField, order, orderStatus)
}

func (t *OrdersService) ListOrdersByWhoForMall(who *common.Who, orderCode string, orderType int, shopid int64, page, psize int, orderField, order string, orderStatus int) ([]*SysOrders, int64, error) {
	return t.tbOrders.ListSysOrdersByWhoForMall(who, orderCode, orderType, shopid, page, psize, orderField, order, orderStatus)
}

/* 根据id获取记录
 * -----------------
 */
func (t *OrdersService) GetOrdersById(id int64) *SysOrders {
	return t.tbOrders.RecodeById(id)
}

func (t *OrdersService) GetOrdersByOutTradeNo(who *common.Who, id int64) *SysOrders {
	return t.tbOrders.RecodeById(id)
}

func (t *OrdersService) GetOrdersAndDetailById(id int64) *SysOrders {
	order := t.tbOrders.RecodeById(id)
	if order == nil {
		return nil
	}

	detaillist := t.tbOrderDetail.ListByOrderId(id)
	order.OrderDetails = detaillist

	return order
}


func (t *OrdersService) GetOrdersByWho(who *common.Who, id int64) *SysOrders {
	return t.tbOrders.RecodeByWho(who, id)
}

/* 添加
 * -----------------
 */
func (t *OrdersService) SaveOrders(item2add *SysOrders) bool {
	return t.tbOrders.AddRecode(item2add)
}

/* 删除(硬删除)*/
func (t *OrdersService) DelOrdersById(id int64) bool {
	return t.tbOrders.DelRecodeById(id)
}

/* 更新
 * -----------------*/
func (t *OrdersService) UpdateOrders(rc *SysOrders) bool {
	return t.tbOrders.UpdateRecode(rc)
}



func (t *OrdersService) UnifiedOrderByWho(who *common.Who, productId int64, specId int64) (*SysOrders, *SysOrderDetail, error) {
	// TODO如何防止重复下单

	product, spec, err := t.appProductService.GetAppProductAndSpecByIdSpecIdAndMiniAppId(productId, specId, who.MiniAppId)
	if err != nil {
		return nil, nil, err
	}


	s := lego.NewDBSession()
	defer s.Close()
	_ = s.Begin()
	orderItem2add := new(SysOrders)
	orderItem2add.Uid = who.Uid
	orderItem2add.TenantId = who.TenantId
	orderItem2add.MiniAppId = who.MiniAppId
	orderItem2add.OrderType = common.AppOrderType_MiniApp //TODO 以后有多种类型，再做区分
	isSuccess := t.tbOrders.AddRecodeWithsession(s.GetSession(), orderItem2add)
	if isSuccess != true {
		s.Rollback()
		return nil, nil, errors.New("tbOrders.AddRecodeWithsession failed")
	}

	orderDetail2add := new(SysOrderDetail)
	orderDetail2add.ProductId =  productId
	orderDetail2add.SpecId = specId
	orderDetail2add.OrderId = orderItem2add.Id
	orderDetail2add.SellPrice = spec.SellPrice
	orderDetail2add.SpecName = spec.SpecName
	orderDetail2add.BarCode = spec.BarCode

	orderDetail2add.DefaultImage = product.DefaultImage
	orderDetail2add.ItemNo = product.ItemNo
	orderDetail2add.ProductName = product.ProductName

	isSuccess = t.tbOrderDetail.AddRecodeWithsession(s.GetSession(), orderDetail2add)
	if isSuccess != true {
		s.Rollback()
		return nil, nil, errors.New("tbOrderDetail.AddRecodeWithsession failed")
	}

	s.Commit()
	return orderItem2add, orderDetail2add, nil
}


func (t *OrdersService) PayAction(payNotify *pay.PayNotify) error {
	var who common.Who
	attachStr := payNotify.Attach
	err := json.Unmarshal([]byte(attachStr), &who)
	if err != nil {
		return err
	}

	orderUpdate := new(SysOrders)
	orderUpdate.Id, err = utils.StringToInt64(payNotify.OutTradeNo)
	if err != nil {
		lego.LogError(err) //接口调试后，一般很难会进入这个分支
		return err
	}

	orderUpdate.IfPay = common.STATE_YES
	t.tbOrders.UpdateRecode(orderUpdate)

	whoForCheck := t.appTenantUserRelService.GetAppTenantUserRelByWho(who) //TODO: 这里后面可以移到一个中间件中，统一处理，这里目的是校验传过来的who
	if whoForCheck == nil {
		return fmt.Errorf("not found who<%s>", who.ToString())
	}

	tenant := new(Tenant)
	tenant.Id = who.TenantId
	tenant.IsPayed = common.STATE_YES //设置已支付状态
	t.tenantService.UpdateTenant(tenant)

	orderId, _ := utils.StringToInt64(payNotify.OutTradeNo)

	order := t.GetOrdersAndDetailById(orderId)
	if order == nil {
		return fmt.Errorf("not found orderId<%d>", orderId)
	}

	if len(order.OrderDetails) <= 0 {
		return fmt.Errorf("not found orderSpecId<%d>", orderId)
	}

	err = t.AppManagerService.ConsumeAppProduct(&who, order.OrderDetails[0].ProductId, order.OrderDetails[0].SpecId)
	if err != nil {
		return err
	}

	orderUpdate.IfFinish = common.STATE_YES
	t.tbOrders.UpdateRecode(orderUpdate)

	return nil
}





func (t *OrdersService) RefundByWho(who *common.Who, OrderId int64) (*pay.RefundResponse, error) {
	// TODO如何防止重复下单
	order := t.tbOrders.RecodeByIdWithWho(who, OrderId)
	if order == nil {
		return nil, fmt.Errorf("not found OrderId(%d)", OrderId)
	}

	var refundReq pay.RefundRequest
	refundReq.OutTradeNo = utils.Int64ToString(OrderId)
	refundReq.OutRefundNo = utils.Int64ToString(OrderId)
	refundReq.TotalFee = 1 //int64(order.ProAmount)
	refundReq.RefundFee = 1 //int64(order.ProAmount)
	resp, err := t.wxPayService.RefundByAppWho(who, refundReq)
	if err != nil {
		return nil, err
	}

	return resp, nil
}

func (t *OrdersService) WithdrawByWho(who *common.Who, req *promotion.TransferReqPara) (*promotion.TransferRespData, error) {
	// TODO如何防止重复下单
	wxUser := t.wxUserService.GetWxUserByUid(who.Uid)
	if wxUser == nil {
		return nil, fmt.Errorf("not found uid(%d)", who.Uid)
	}

	req.Openid = wxUser.OpenId
	req.CheckName = promotion.NO_CHECK
	req.PartnerTradeNo = utils.Int64ToString(lego.UUID()) //临时这样 TODO
	/*向平台提现
	要查看租户的余额，提取后要减去提取部分
	检查用户是否有租户余额的提现权限，目前只有超级管理员才有提现权限
	 */

	resp, err := t.wxPayService.WithdrawByUserWho(who, req)
	if err != nil {
		return nil, err
	}

	return resp, nil
}
